package cn.mall.order.service.impl;

import cn.mall.base.utils.AjaxResult;
import cn.mall.base.constants.BaseConstants;
import cn.mall.bill.domain.Bill;
import cn.mall.bill.mapper.BillMapper;
import cn.mall.order.domain.Order;
import cn.mall.order.dto.FllowDto;
import cn.mall.order.mapper.OrderMapper;
import cn.mall.order.utils.ConmentUtils;
import cn.mall.order.utils.Utils;
import cn.mall.base.utils.VideoUtils;
import cn.mall.order.utils.WeiboDataAsync;
import cn.mall.order.utils.WeiboDataCacheUtils;
import cn.mall.user.domain.User;
import cn.mall.user.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

/**
 * 订单数据监控服务
 * 负责异步跟踪和更新订单数据，提高下单性能
 */
@Service
public class OrderDataMonitorService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderDataMonitorService.class);
    
    // 订单异常状态，数据获取失败三次后设置
    private static final int ORDER_STATE_EXCEPTION = 6;
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private BillMapper billMapper;
    
    @Autowired
    private WeiboDataAsync dataCollector;
    
    @Autowired
    private WeiboDataCacheUtils weiboDataCacheService;
    
    // 待处理订单队列
    private final ConcurrentLinkedQueue<Order> pendingOrders = new ConcurrentLinkedQueue<>();
    
    // 跟踪订单重试次数
    private final Map<String, Integer> orderRetryCount = new ConcurrentHashMap<>();
    
    /**
     * 将订单添加到监控队列
     * 
     * @param order 需要监控的订单
     */
    public void addOrderToMonitor(Order order) {
        pendingOrders.offer(order);
        logger.debug("订单已添加到监控队列，订单号: {}", order.getOId());
    }
    
    /**
     * 将订单添加到监控队列的最前端（高优先级）
     * 用于管理员手动触发订单数据获取
     * 
     * @param order 需要高优先级处理的订单
     */
    public void addOrderToMonitorWithHighPriority(Order order) {
        // 首先从队列中移除该订单（如果存在）
        List<Order> currentQueue = new ArrayList<>();
        boolean exists = false;
        
        // 遍历当前队列
        while (!pendingOrders.isEmpty()) {
            Order queuedOrder = pendingOrders.poll();
            if (queuedOrder != null) {
                // 如果订单ID相同，则不再添加到临时列表（去重）
                if (queuedOrder.getOId() != null && queuedOrder.getOId().equals(order.getOId())) {
                    exists = true;
                    continue;
                }
                currentQueue.add(queuedOrder);
            }
        }
        
        // 重置重试计数（如果存在）
        orderRetryCount.remove(order.getOId());
        
        // 首先添加需要高优先级处理的订单
        pendingOrders.offer(order);
        
        // 然后添加原有的订单
        for (Order queuedOrder : currentQueue) {
            pendingOrders.offer(queuedOrder);
        }
        
        logger.info("订单已添加到监控队列最前端（高优先级），订单号: {}", order.getOId());
    }
    
    /**
     * 定时处理队列中的订单数据更新
     * 每1分钟执行一次，优先处理新订单
     */
    @Scheduled(fixedRate = 60000)
    public void processMonitoredOrders() {
        int processCount = 0;
        List<Order> retryOrders = new ArrayList<>();
        
        logger.info("开始处理订单数据更新，当前待处理订单数: {}", pendingOrders.size());
        
        while (!pendingOrders.isEmpty() && processCount < 50) {
            Order order = pendingOrders.poll();
            if (order != null) {
                try {
                    logger.info("开始处理订单数据，订单号: {}, 商品类型: {}, URL: {}", 
                        order.getOId(), 
                        order.getGoods() != null ? order.getGoods().getType() : "未知",
                        order.getUrl());
                    
                    // 刷新订单数据
                    boolean success = processOrderData(order);
                    
                    if (!success) {
                        // 获取当前重试次数
                        int retryCount = orderRetryCount.getOrDefault(order.getOId(), 0);
                        
                        if (retryCount < 2) { // 最多重试2次，总共3次尝试
                            // 更新重试次数
                            orderRetryCount.put(order.getOId(), retryCount + 1);
                            // 添加到重试列表
                            retryOrders.add(order);
                            logger.warn("订单数据获取失败，将进行重试。订单号: {}，当前重试次数: {}", order.getOId(), retryCount + 1);
                        } else {
                            // 超过最大重试次数，执行退款流程
                            processOrderRefund(order);
                            logger.error("订单数据获取失败超过最大重试次数，已退款。订单号: {}", order.getOId());
                        }
                    } else {
                        // 数据获取成功，移除重试计数
                        orderRetryCount.remove(order.getOId());
                        logger.info("订单数据获取成功并已更新到数据库，订单号: {}", order.getOId());
                    }
                    
                    processCount++;
                } catch (Exception e) {
                    logger.error("处理订单数据更新异常，订单号: " + order.getOId(), e);
                    // 异常情况下也添加到重试队列
                    retryOrders.add(order);
                }
            }
        }
        
        // 将需要重试的订单重新加入队列的前端（优先处理）
        List<Order> currentQueue = new ArrayList<>();
        while (!pendingOrders.isEmpty()) {
            currentQueue.add(pendingOrders.poll());
        }
        
        // 先添加需要重试的订单
        for (Order order : retryOrders) {
            pendingOrders.offer(order);
        }
        
        // 再添加原来的订单
        for (Order order : currentQueue) {
            pendingOrders.offer(order);
        }
        
        logger.info("订单数据批量更新完成，处理了 {} 条订单，其中 {} 条需要重试", processCount, retryOrders.size());
    }
    
    /**
     * 处理单个订单的数据更新
     * 
     * @param order 订单
     * @return 是否成功获取数据
     */
    private boolean processOrderData(Order order) {
        try {
            // 根据不同的商品类型处理不同的数据采集
            Integer type = order.getGoods().getType();
            
            if (type == 1) {
                // 关注类型
                return processFollowOrder(order);
            } else if (type == 6) {
                // 视频类型
                return processVideoOrder(order);
            } else if (type == 5) {
                // 类型5无需采集数据
                order.setSFollow(1);
                orderMapper.update(order);
                return true;
            } else if (type == 10) {
                // 内评赞类型
                return processCommentLikeOrder(order);
            } else {
                // 其他类型（转发、评论、点赞等）
                return processBaseOrder(order);
            }
        } catch (Exception e) {
            logger.error("处理订单数据失败，订单号: " + order.getOId(), e);
            return false;
        }
    }
    
    /**
     * 处理关注类型订单
     */
    private boolean processFollowOrder(Order order) {
        try {
            String fllow = Utils.getFllow();
            String subValue = Utils.getSubValue(fllow);
            FllowDto fllowDto = new FllowDto();
            fllowDto.setSub(subValue);
            fllowDto.setUrl(order.getUrl());
            Integer followdata = Utils.getFollowdata(fllowDto);
            
            order.setSFollow(followdata);
            // 更新订单
            orderMapper.update(order);
            
            // 缓存数据
            weiboDataCacheService.cacheFollowData(order.getUrl(), followdata);
            
            return true;
        } catch (Exception e) {
            logger.error("处理关注订单数据失败，订单号: " + order.getOId(), e);
            return false;
        }
    }
    
    /**
     * 处理视频类型订单
     */
    private boolean processVideoOrder(Order order) {
        try {
            AjaxResult ajaxResult = VideoUtils.ToolUtils(order.getUrl());
            if (!ajaxResult.getSuccess()) {
                logger.warn("视频数据获取失败，订单号: {}", order.getOId());
                return false;
            }
            
            String videoData = (String) ajaxResult.getResultObj();
            if (videoData == null) {
                logger.warn("视频数据为空，订单号: {}", order.getOId());
                return false;
            }
            
            Integer sv = VideoUtils.convertToWan(videoData);
            order.setSVideo(sv);
            // 更新订单
            orderMapper.update(order);
            
            // 缓存数据
            weiboDataCacheService.cacheVideoData(order.getUrl(), sv);
            
            return true;
        } catch (Exception e) {
            logger.error("处理视频订单数据失败，订单号: " + order.getOId(), e);
            return false;
        }
    }
    
    /**
     * 处理内评赞类型订单
     */
    private boolean processCommentLikeOrder(Order order) {
        try {
            String taskid = order.getRefundNumber();
            AjaxResult result = ConmentUtils.GetComment(taskid);
            
            if (!result.getSuccess()) {
                logger.warn("内评赞数据获取失败，订单号: {}", order.getOId());
                return false;
            }
            
            String s1 = (String) result.getResultObj();
            if (s1 == null) {
                logger.warn("内评赞数据为空，订单号: {}", order.getOId());
                return false;
            }
            
            Integer sg = VideoUtils.convertToWan(s1);
            order.setSGood(sg);
            // 更新订单
            orderMapper.update(order);
            
            // 缓存数据
            weiboDataCacheService.cacheCommentGoodData(taskid, sg);
            
            return true;
        } catch (Exception e) {
            logger.error("处理内评赞订单数据失败，订单号: " + order.getOId(), e);
            return false;
        }
    }
    
    /**
     * 处理基础类型订单（转发、评论、点赞等）
     */
    private boolean processBaseOrder(Order order) {
        try {
            String url = order.getUrl();
            if (!url.contains("m.weibo.cn")) {
                url = Utils.dealStr(url);
            }
            
            AjaxResult result = Utils.ToolUtils(url);
            if (!result.getSuccess() || result.getResultObj() == null) {
                logger.warn("基础数据获取失败，订单号: {}", order.getOId());
                return false;
            }
            
            ArrayList<Integer> arrayList = (ArrayList<Integer>) result.getResultObj();
            order.setSForward(arrayList.get(0));
            order.setSComment(arrayList.get(1));
            order.setSGood(arrayList.get(2));
            
            if (order.getGoods().getType() == 7) {
                //是否真人转评赞
                order.setCompletionSf(0);
                order.setCompletionSc(0);
                order.setCompletionSg(0);
                order.setSurplusSf(order.getCount());
                order.setSurplusSc(order.getCount());
                order.setSurplusSg(order.getCount());
            }
            
            // 更新订单
            orderMapper.update(order);
            
            // 缓存数据
            weiboDataCacheService.cacheBaseData(url, arrayList);
            
            return true;
        } catch (Exception e) {
            logger.error("处理基础订单数据失败，订单号: " + order.getOId(), e);
            return false;
        }
    }
    
    /**
     * 处理订单退款
     * 当多次尝试获取数据失败后，自动退款
     */
    @Transactional
    public void processOrderRefund(Order order) {
        try {
            // 1. 获取最新订单状态
            Order updatedOrder = orderMapper.loadByOid(order.getOId());
            
            // 如果订单状态已经不是待处理，则不进行退款处理
            if (updatedOrder.getOType() != BaseConstants.Order.STATE_PENDORDER) {
                logger.info("订单状态已变更，不需要退款。订单号: {}, 当前状态: {}", updatedOrder.getOId(), updatedOrder.getOType());
                return;
            }
            
            // 2. 设置订单状态为异常
            updatedOrder.setOType(ORDER_STATE_EXCEPTION);
            orderMapper.update(updatedOrder);
            
            // 3. 退还用户余额
            User user = userMapper.loadById(updatedOrder.getUId());
            user.setBalance(user.getBalance().add(updatedOrder.getFinalPrice()));
            userMapper.update(user);
            
            // 4. 创建退款账单记录
            Bill bill = new Bill();
            bill.setMoney(updatedOrder.getFinalPrice());
            bill.setType(3); // 退款类型
            bill.setBtype(3); // 退款业务类型
            
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String formattedDate = sdf.format(new Date());
            bill.setTime(formattedDate);
            bill.setUserid(updatedOrder.getUId());
            bill.setBalance(user.getBalance());
            bill.setOid(updatedOrder.getOId());
            bill.setUrl(updatedOrder.getUrl());
            
            billMapper.insert(bill);
            
            logger.info("订单自动退款完成，订单号: {}, 退款金额: {}", updatedOrder.getOId(), updatedOrder.getFinalPrice());
        } catch (Exception e) {
            logger.error("处理订单退款失败，订单号: " + order.getOId(), e);
            throw e; // 重新抛出异常，触发事务回滚
        }
    }
    
    /**
     * 定时加载近期待处理订单进行监控
     * 每小时执行一次
     */
    @Scheduled(fixedRate = 3600000)
    public void loadRecentPendingOrders() {
        try {
            // 获取最近创建的待处理订单
            List<Order> recentOrders = orderMapper.findRecentPendingOrders(100);
            
            int addedCount = 0;
            for (Order order : recentOrders) {
                // 跳过已经在队列中的订单
                String oid = order.getOId();
                if (!orderRetryCount.containsKey(oid)) {
                    pendingOrders.offer(order);
                    addedCount++;
                }
            }
            
            logger.info("已加载 {} 条最近的待处理订单到监控队列", addedCount);
        } catch (Exception e) {
            logger.error("加载最近待处理订单失败", e);
        }
    }
} 